﻿using System;
using System.Reflection;
using System.Threading.Tasks;
using Fast.Reflection;

namespace Fast.DynamicProxies
{
    /// <summary>
    /// 动态代理类
    /// </summary>
    [SkipScan]
    public class DynamicProxy : AspectDispatchProxy, IDispatchProxy
    {
        /// <summary>
        /// 动作之前执行
        /// </summary>
        private Action<object[]> _beforeAction { get; set; }

        /// <summary>
        /// 动作之后执行
        /// </summary>
        private Action<object[], object> _afterAction { get; set; }

        /// <summary>
        /// 实例对象
        /// </summary>
        public object Decorated { get; set; }

        /// <summary>
        /// 创建代理类
        /// </summary>
        /// <param name="decorated"></param>
        /// <param name="beforeAction"></param>
        /// <param name="afterAction"></param>
        /// <returns></returns>
        public static T Create<T>(T decorated, Action<object[]> beforeAction, Action<object[], object> afterAction)
        {
            var proxy = Create<T, DynamicProxy>();
            (proxy as DynamicProxy).Decorated = decorated;
            (proxy as DynamicProxy)._beforeAction = beforeAction;
            (proxy as DynamicProxy)._afterAction = afterAction;

            return proxy;
        }

        /// <summary>
        /// 代理类执行时 Invoke方法
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            _beforeAction?.Invoke(args);
            var result = targetMethod.Invoke(Decorated, args);
            _afterAction?.Invoke(args, result);
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected override Task InvokeAsync(MethodInfo targetMethod, object[] args)
        {
            return (Task)Invoke(targetMethod, args);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="targetMethod"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected override Task<T> InvokeWithResultAsync<T>(MethodInfo targetMethod, object[] args)
        {
            return (Task<T>)Invoke(targetMethod, args);
        }
    }
}
